# -*- coding;utf-8 -*-
"""
File name : ReadDocx2QuestionListVocational.py
Program IDE : PyCharm
Create file time: 2023/10/3 21:54
File Create By Author : 朱清闯
"""

try:
    from xml.etree.cElementTree import XML
except ImportError:
    from xml.etree.ElementTree import XML
import zipfile
import xml.dom.minidom as xdom
import re
from utils.uploadfile import get_new_name
import shutil
import os
from django.conf import settings


grade_rule_list = [r'(高考|高一|高二|高三)', r'(中考|九年级|八年级|七年级)', r'(六年级|五年级|四年级|三年级|二年级|一年级)']
grade_rule = grade_rule_list[settings.SEGMENT]
blank_char = re.compile('[\u3000|\xa0]')
question_choice_or_cloze_rule = r'^[一二三四]、(选择题|单项选择题|填空题|非选择题|多项选择题|判断题|是非选择题)[\(（]'  # 匹配选择题或者填空题如一、选择题 二、填空题
question_type_rule = r"^[一二三四]、(选择题|单项选择题|填空题|非选择题|多项选择题|判断题|是非选择题)[\(（]"  # 匹配题型，如一、选择题
question_number_rule = r"^(\.|．){0,3}(\d{1,3})(\.|．){1}(.*)"  # 匹配小题号，如段首以1.开头, 并跳过开头加重点符号
answer_rule = r"^【答案】(.*)"  # 匹配答案，如【答案】xxx
explain_rule = r'^【解析】(.*)'  # 匹配解析，如【解析】xxx
difficulty_rule = r'^【难度】(\d)'
pattern_get_image_target = r"media/image\d{1,2}(.\w+)"
patten_image_name = r'media/(image\d{1,2}.\w+)'
pattern_del_tag = re.compile(r'<[^>]+>')  # 去掉标签<w:t>
pattern_get_text_between = r'>(.+)<'
pattern_get_imageId = r"(rId[\d+])"
pattern_date_rule = r'20(1|2)\d[-年]\d{1,2}[-月]\d{1,2}日*'
pattern_date_year_rule = r'(20\d{2})(年|届|学年)'
pattern_date_month_rule = r'(\d{1,2})月'
precondition_rule = r'阅读(下列|以下)材料,回答第(\d{1,2})[至-](\d{1,2})小{0,1}题'
pattern_answer_vocational_rule = '参考答案'
image_dict = {}
type_dic = {'简答题': 0, '选择题': 1, '单项选择题': 1, '填空题': 2, '非选择题': 2, '多项选择题': 3, '判断题': 4, '是非选择题': 4}
grade_dic_list = [{'高三': '3', '高二': '2', '高一': '1', '选考': '4', '高考': '4'},
                  {'中考': '4', '九年级': '3', '八年级': '2', '七年级': '1'},
                  {'六年级': 6, '五年级': 5, '四年级': 4, '三年级': 3, '二年级': 2, '一年级': 1}
                  ]
grade_dic = grade_dic_list[settings.SEGMENT]
paper_dict = {'title': '', 'publish_time': '', 'grade': 3, 'open_level': 'public'}


# 检测题目是否连续，即漏题和赠题
def verify_question_number(question_list):
    flag = True
    q_index = 0
    for q_index in range(len(question_list)-1):
        if question_list[q_index]['order'] + 1 != question_list[q_index+1]['order']:
            flag = False
            break
    return flag, q_index+1


def get_table(element):
    w_trs = element.getElementsByTagName("w:tr")
    rows_text = []  # 存放行的文本
    for r_index, tr in enumerate(w_trs):
        # 获取所有的单元格
        cells = tr.getElementsByTagName("w:tc")
        cells_text = []  # 存放单元格的文本
        for c_index, cell in enumerate(cells):
            # 获取所有的文本
            wts = cell.getElementsByTagName("w:t")
            for wt in wts:  # 把文本拼接
                text_temp = re.search(pattern_get_text_between, wt.toxml())
                if text_temp:
                    text_temp = text_temp.group(1).strip()
                    cells_text.append(text_temp)
        rows_text.append(cells_text)
    # print(rows_text)  # 打印结果，二维数组
    return rows_text


def get_text_in_paragraph(paragraph):
    """
    获取一个段落内的所有文字
    """
    wts = paragraph.getElementsByTagName("w:t")  # 获取该段落内的所有的可见文本
    p_text = ""
    for wt in wts:
        t_text = pattern_del_tag.sub('', wt.toxml())
        p_text += t_text
    return p_text


def get_images_in_paragraph(element):
    """获取一个段落内的所有图片的url，并用-号连接各个url"""
    wds = element.getElementsByTagName("a:blip")  # 获取该段落内的所有的图片
    images = ""
    for image in wds:
        image_name = image.getAttribute("r:embed")
        image_url = image_dict[image_name]  # 获取图片rul
        images += image_url + '-'
    if images:
        images = images[:-1]
    return images


def store_images_to_dict(root):
    """把所有的图片先保存到字典中，便于后期直接用id对应取出value"""
    relation_ships = root.getElementsByTagName("Relationship")
    for relation_ship in relation_ships:
        target = relation_ship.getAttribute("Target")
        image_id = relation_ship.getAttribute("Id")
        if target and re.match(pattern_get_image_target, target):
            src_file = 'word/' + target
            dst_dir = os.path.join(settings.BASE_DIR).replace('\\', '/') + settings.IMAGE_URL
            shutil.copy(src_file, dst_dir)
            suffix = re.match(pattern_get_image_target, target).group(1)
            src_name = dst_dir + re.match(patten_image_name, target).group(1)
            image_name = get_new_name() + suffix
            new_name = dst_dir + image_name
            os.rename(src_name, new_name)
            images_url = settings.IMAGE_URL + image_name
            image_dict[image_id] = images_url


def get_docx_text_vocational(path):
    questions_list = []  # 存放所有题目
    question_index = 0
    # 开始切题的标志，当设置题型后，开始切题，跳过注意事项，比如1.所有试题均需在答题纸上作答；该部分跟题号有混淆。
    question_start_flag = False
    content = ''
    # 存放是否来到答案部分
    is_answer_section = False
    question_dict = {"content": "", "answer": "", "explain": "", "type": 1, "pictures": "", "pictures_explain": "",
                     "reference": "", "difficulty_level": 3, "knowledgepoint": -1, "knowledgepoint_cn": '待选',
                     "content_table": [], "explain_table": [], 'order': 0
                     }
    with zipfile.ZipFile(path, 'r') as zfile:
        zfile.extractall()
    # 以下读取所有图片文件，并一id为key,图片在服务器的url为value
    image_rels = xdom.parse('word/_rels/document.xml.rels')
    root1 = image_rels.documentElement
    store_images_to_dict(root1)

    # 初始化拿到第一个body标签
    xp = xdom.parse('word/document.xml')
    root = xp.documentElement
    bodies = root.getElementsByTagName("w:body")
    body = bodies[0]

    current_type_cn = '单项选择题'
    current_type = type_dic[current_type_cn]
    question_dict["type"] = current_type
    question_dict['type_cn'] = current_type_cn
    node_index = 0
    # 第一行试卷的标题填入“reference”字段，并填入paper的标题
    paragraph = body.childNodes[node_index]
    paragraph_text = get_text_in_paragraph(paragraph)
    # 用while是因为跳过空行段落,来到第一行
    while paragraph_text.strip() == '' or not re.search(pattern_date_year_rule, paragraph_text):
        node_index += 1
        paragraph = body.childNodes[node_index]
        paragraph_text = get_text_in_paragraph(paragraph)
    reference = paragraph_text.strip()
    question_dict["reference"] = reference
    paper_dict['title'] = reference
    # 第一行中提取试卷的时间，字典中填入“publish_time”字段
    publish_time = ''
    publish_year = ''
    if re.search(pattern_date_year_rule, paragraph_text):
        publish_year = re.search(pattern_date_year_rule, paragraph_text).group(1)
        publish_time += publish_year
    if re.search(pattern_date_month_rule, paragraph_text):
        publish_month = re.search(pattern_date_month_rule, paragraph_text).group(1)
        if publish_year != '':
            publish_time = publish_year + "-" + publish_month + "-" + "1"
            paper_dict["publish_time"] = publish_time
            question_dict['publish_time'] = publish_time

    # 第二行之后是题目的题型，字典中填入“type”字段
    node_index += 1
    paragraph = body.childNodes[node_index]
    paragraph_text = get_text_in_paragraph(paragraph)
    while paragraph_text.strip() == '' or not re.search(question_choice_or_cloze_rule, paragraph_text):
        node_index += 1
        paragraph = body.childNodes[node_index]
        paragraph_text = get_text_in_paragraph(paragraph)
    if re.search(question_choice_or_cloze_rule, paragraph_text):
        current_type_cn = re.search(question_choice_or_cloze_rule, paragraph_text).group(1)
        question_dict["type_cn"] = current_type_cn
        question_dict["type"] = type_dic[current_type_cn]
        question_start_flag = True

    # 从第3行开始收集题目，跳过空行
    node_index += 1
    paragraph = body.childNodes[node_index]
    paragraph_text = get_text_in_paragraph(paragraph)
    while paragraph_text.strip() == '':
        node_index += 1
        paragraph = body.childNodes[node_index]
        paragraph_text = get_text_in_paragraph(paragraph)
    while node_index < len(body.childNodes):
        element = body.childNodes[node_index]
        ele_name = element.nodeName
        # 以下获取可见文本和图片，因此都在<w:p>便签内
        if ele_name == "w:p" and not is_answer_section:
            p_text = get_text_in_paragraph(element)
            p_text = blank_char.sub(' ', p_text).replace("（", "(").replace('）', ')').replace('，', ',')
            if p_text:
                # 匹配题型，如二、非选择题
                if re.match(question_type_rule, p_text):

                    if question_dict["content"]:
                        questions_list.append(question_dict)
                    current_type_cn = re.match(question_type_rule, p_text).group(1)
                    question_dict = {"content": "", "answer": "", "explain": "", "type": type_dic[current_type_cn],
                                     "type_cn": current_type_cn, "pictures": "", "content_table": [],
                                     "explain_table": [], 'order': 0,
                                     "pictures_explain": "", "reference": reference, "difficulty_level": 3,
                                     "knowledgepoint": -1, "knowledgepoint_cn": '待选', 'publish_time': publish_time
                                     }
                # 匹配到题号，比如1.以下xxx, 先结算上一题的内容，添加到列表，再清空题目字典，最后把本行文本加入到新题目字典中，以及题号
                elif re.search(question_number_rule, p_text.strip(), re.M) and question_start_flag:
                    if question_dict["content"] != '':
                        questions_list.append(question_dict)
                        question_dict = {"content": "", "answer": "", "explain": "", "type_cn": current_type_cn,
                                         'type': type_dic[current_type_cn], "pictures": "", "content_table": [],
                                         "explain_table": [], "pictures_explain": "", "reference": reference,
                                         "difficulty_level": 3, "knowledgepoint": -1, 'publish_time': publish_time,
                                         "knowledgepoint_cn": '待选', 'order': 0}
                    content = re.search(question_number_rule, p_text, flags=re.M).group(4)
                    order = re.search(question_number_rule, p_text, flags=re.M).group(2)
                    question_dict['content'] = content
                    question_dict['order'] = int(order)
                # 匹配到参考答案，检测前面的题目切题有没有错误
                elif re.search(pattern_answer_vocational_rule, p_text.strip(), re.M):
                    if question_dict['content'] != '':
                        questions_list.append(question_dict)
                    # print("所有题目：", questions_list)
                    flag, q_index = verify_question_number(question_list=questions_list)
                    if not flag:
                        # print("第", q_index, '题切题错误')
                        return [], {'error_number': q_index}, False
                    is_answer_section = True
                    continue
                # 非空行的文本内容，则按照解析有内容优先，再如果答案有内容优先，最后填充题目
                else:
                    if question_dict['content'] != '':
                        question_dict['content'] += '\n' + p_text
            # 获取该段落内的所有的图片
            p_images = get_images_in_paragraph(element)
            if p_images:
                if question_dict["pictures"] == "":
                    question_dict['pictures'] = p_images
                else:
                    question_dict["pictures"] += "-" + p_images

        # 以下获取表格内容，填入相应题目的答案
        elif ele_name == "w:tbl" and is_answer_section:
            table = get_table(element)
            if table:
                for row_index in range(0, len(table), 2):
                    for column_index in range(1, len(table[row_index])):
                        # print("索引号：", question_number)
                        # 检测之前的切题的题目和当前答案的题号是否一致，如果有漏题和增题，则返回当前对应好的题目列表
                        if questions_list[question_index]['order'] == int(table[row_index][column_index]):
                            questions_list[question_index]['answer'] = table[row_index + 1][column_index]
                            question_index += 1
                        else:
                            # print("第", question_number, '题答案重复')
                            question_index = 0
                            return questions_list, paper_dict, False
        node_index += 1
    # if question_dict["content"]:
    #     questions_list.append(question_dict)
    #     question_dict = {"content": "", "answer": "", "explain": "", "type_cn": '选择题', 'publish_time': '',
    #                      'type': 1, "pictures": "", "content_table": [], "explain_table": [],
    #                      "pictures_explain": "", "reference": '', "difficulty_level": 3, "knowledgepoint": -1,
    #                      "knowledgepoint_cn": '待选', 'order':0}
    return questions_list, paper_dict, True


def get_docx_text(path):
    # 以下变量用于记录前置情境内容
    precondition_number_start = precondition_number_end = -1
    precondition_content = ""
    precondition_pictures = ''
    precondition_collect_over = True  # 收集前置情境是否结束
    questions_list = []  # 存放所有题目
    question_dict = {"content": "", "answer": "", "explain": "", "type": 1, "pictures": "", 'pictures_answer': '',
                     "pictures_explain": "", "reference": "", "difficulty_level": 3, "knowledgepoint": -1,
                     "knowledgepoint_cn": '待选', "content_table": [], "explain_table": [], 'answer_table': []
                     }
    with zipfile.ZipFile(path, 'r') as zfile:
        zfile.extractall()
    # 以下读取所有图片文件，并一id为key,图片在服务器的url为value
    image_rels = xdom.parse('word/_rels/document.xml.rels')
    root1 = image_rels.documentElement
    store_images_to_dict(root1)

    # 初始化拿到第一个body标签
    xp = xdom.parse('word/document.xml')
    root = xp.documentElement
    bodies = root.getElementsByTagName("w:body")
    body = bodies[0]

    current_type_cn = '选择题'
    current_type = type_dic[current_type_cn]
    question_dict["type"] = current_type
    question_dict['type_cn'] = current_type_cn
    node_index = 0
    # 第一行试卷的标题填入“reference”字段，并填入paper的标题
    paragraph = body.childNodes[node_index]
    paragraph_text = get_text_in_paragraph(paragraph)
    # 用while是因为跳过空行段落,来到第一行
    while paragraph_text.strip() == '':
        node_index += 1
        paragraph = body.childNodes[node_index]
        paragraph_text = get_text_in_paragraph(paragraph)
    reference = paragraph_text.strip()
    question_dict["reference"] = reference
    paper_dict['title'] = reference

    # 第一行中提取年级，并存入"grade"字段
    if re.search(grade_rule, paragraph_text):
        grade = grade_dic[re.search(grade_rule, paragraph_text).group(1)]
        paper_dict["grade"] = grade
    publish_time = ''
    publish_year = ''
    # 第一行中提取试卷的时间，字典中填入“publish_time”字段
    if re.search(pattern_date_year_rule, paragraph_text):
        publish_year = re.search(pattern_date_year_rule, paragraph_text).group(1)
        publish_time += publish_year
    if re.search(pattern_date_month_rule, paragraph_text):
        publish_month = re.search(pattern_date_month_rule, paragraph_text).group(1)
        if publish_year != '':
            publish_time = publish_year + "-" + publish_month + "-" + "1"
            paper_dict["publish_time"] = publish_time
            question_dict['publish_time'] = publish_time

    # 第二行是题目的题型，字典中填入“type”字段
    node_index += 1
    paragraph = body.childNodes[node_index]
    paragraph_text = get_text_in_paragraph(paragraph)
    while paragraph_text.strip() == '':
        node_index += 1
        paragraph = body.childNodes[node_index]
        paragraph_text = get_text_in_paragraph(paragraph)
    if re.search(question_choice_or_cloze_rule, paragraph_text):
        current_type_cn = re.search(question_choice_or_cloze_rule, paragraph_text).group(1)
        question_dict["type_cn"] = current_type_cn
        question_dict["type"] = type_dic[current_type_cn]

    # 从第3行开始收集题目，跳过空行
    node_index += 1
    paragraph = body.childNodes[node_index]
    paragraph_text = get_text_in_paragraph(paragraph)
    while paragraph_text.strip() == '':
        node_index += 1
        paragraph = body.childNodes[node_index]
        paragraph_text = get_text_in_paragraph(paragraph)
    while node_index < len(body.childNodes):
        element = body.childNodes[node_index]
        ele_name = element.nodeName
        # 以下获取可见文本和图片，因此都在<w:p>便签内
        if ele_name == "w:p":
            p_text = get_text_in_paragraph(element)
            p_text = blank_char.sub(' ', p_text).replace("（", "(").replace('）', ')').replace('，', ',')
            if p_text:
                # 匹配题型，如二、非选择题
                if re.match(question_type_rule, p_text):
                    if question_dict["content"]:
                        questions_list.append(question_dict)
                    current_type_cn = re.match(question_type_rule, p_text).group(1)
                    question_dict = {"content": "", "answer": "", "explain": "", "type": type_dic[current_type_cn],
                                     "type_cn": current_type_cn, "pictures": "", "content_table": [],
                                     "explain_table": [], 'answer_explain': '', "pictures_answer": "",
                                     "pictures_explain": "", "reference": reference, "difficulty_level": 3,
                                     "knowledgepoint": -1, "knowledgepoint_cn": '待选', 'publish_time': publish_time
                                     }
                # 匹配到题号，比如1.以下xxx, 先结算上一题的内容，添加到列表，再清空题目字典，最后把本行文本加入到新题目字典中，以及题号
                elif re.search(question_number_rule, p_text.strip(), re.M):
                    if question_dict["content"] != '':
                        questions_list.append(question_dict)
                        question_dict = {"content": "", "answer": "", "explain": "", "type_cn": current_type_cn,
                                         'type': type_dic[current_type_cn], "pictures": "", "pictures_answer": "",
                                         "pictures_explain": "", "content_table": [],  "answer_table": [],
                                         "explain_table": [], "reference": reference, "difficulty_level": 3,
                                         "knowledgepoint": -1, 'publish_time': publish_time, "knowledgepoint_cn": '待选',
                                         }
                    content = re.search(question_number_rule, p_text, flags=re.M).group(4)
                    order = re.search(question_number_rule, p_text, flags=re.M).group(2)

                    if precondition_content != "" and precondition_number_start <= int(
                            order) <= precondition_number_end:
                        question_dict['content'] = precondition_content + "\n" + content
                        question_dict['pictures'] = precondition_pictures
                    elif not (precondition_number_start <= int(order) <= precondition_number_end):
                        question_dict['content'] = content
                    if precondition_number_start == int(order):
                        precondition_collect_over = True
                    if int(order) > precondition_number_end:
                        precondition_content = ""
                        precondition_pictures = ""
                    question_dict['order'] = int(order)
                # 匹配到答案
                elif re.search(answer_rule, p_text):
                    answer = re.search(answer_rule, p_text).group(1)
                    question_dict['answer'] = answer
                # 匹配到解析
                elif re.search(explain_rule, p_text):
                    explain = re.search(explain_rule, p_text).group(1)
                    question_dict['explain'] = explain
                # 匹配到难度
                elif re.search(difficulty_rule, p_text):
                    difficulty_level = re.search(difficulty_rule, p_text).group(1)
                    question_dict['difficulty_level'] = int(difficulty_level)
                # 匹配到题目前置情境
                elif re.search(precondition_rule, p_text.strip(), re.M):
                    precondition_number_start = int(re.search(precondition_rule, p_text).group(2))
                    precondition_number_end = int(re.search(precondition_rule, p_text).group(3))
                    precondition_content = p_text
                    # 以下是初始化存储前置情境的变量
                    precondition_collect_over = False
                    precondition_pictures = ""
                # 非空行的文本内容，则按照解析有内容优先，再如果答案有内容优先，最后填充题目
                else:
                    if not precondition_collect_over:
                        precondition_content += '\n' + p_text
                    elif question_dict['explain']:
                        question_dict['explain'] += '\n' + p_text
                    elif question_dict['answer']:
                        question_dict['answer'] += '\n' + p_text
                    elif question_dict['content']:
                        question_dict['content'] += '\n' + p_text
            # 获取该段落内的所有的图片
            p_images = get_images_in_paragraph(element)
            if p_images:
                if not precondition_collect_over:
                    if precondition_pictures == "":
                        precondition_pictures = p_images
                    else:
                        precondition_pictures += '-' + p_images
                elif question_dict["explain"]:
                    if question_dict["pictures_explain"] == "":
                        question_dict["pictures_explain"] = p_images
                    else:
                        question_dict["pictures_explain"] += "-" + p_images
                elif question_dict["answer"]:
                    if question_dict["pictures_answer"] == "":
                        question_dict["pictures_answer"] = p_images
                    else:
                        question_dict["pictures_answer"] += "-" + p_images
                elif question_dict["content"]:
                    if question_dict["pictures"] == "":
                        question_dict['pictures'] = p_images
                    else:
                        question_dict["pictures"] += "-" + p_images

        # 以下获取表格内容，待修改
        # elif ele_name == "w:tbl":
        #     table = get_table(element)
        #     if table:
        #         if question_dict["explain"]:
        #             question_dict["explain_table"] = table
        #         elif question_dict["answer"]:
        #             question_dict["answer_table"] = table
        #         elif question_dict["content"]:
        #             question_dict['content_table'] = table
        node_index += 1
    if question_dict["content"]:
        questions_list.append(question_dict)
        question_dict = {"content": "", "answer": "", "explain": "", "type_cn": '选择题', 'publish_time': publish_time,
                         'type': 1, "pictures": "", "content_table": [], "answer_table": [], "explain_table": [],
                         'pictures_answer': '', "pictures_explain": "", "reference": reference, "difficulty_level": 3,
                         "knowledgepoint": -1, "knowledgepoint_cn": '待选'}
    return questions_list, paper_dict


if __name__ == "__main__":
    result = get_docx_text('test.docx')
